import axios from 'axios'
import Vue from 'vue';
import { Notification } from 'element-ui';
Vue.use(Notification);
function isEmpty(obj){
  if(obj == null || obj == undefined || obj == '' || (obj instanceof Array && obj.length === 0) || (obj instanceof Object && Object.keys(obj).length == 0)){
    return true;
  }
  return false;
}
/*
 * options:发送给后台时携带cookie或者设置headers
   fullSuccess:是否成功的回调函数全部自己定义，如果为true则直接将response.data(后台返回数据在response.data中)放置到resolve中，fullSuccess设置为true后，ignoreEmptyData、hideEmptyTip、showEmptyInfo、emptyDataInfo这四个字段均可以不设置，设置也不会起作用；如果为false，则提示消息全使用此函数默认提示方式，会将response.data[dataKey]放置到resolve中.
   ignoreEmptyData:设置为true，则不判断后台返回的前台使用的数据是否为空的情况，直接进行消息提示，为false则进行提示，默认是提示数据为空，如果hideEmptyTip设置为true，则不提示消息
   hideEmptyTip:数据为空时，是否显示数据为空的消息提示，默认显示消息提示
   showEmptyInfo:数据为空时，是否使用后台返回的消息进行消息提示
   emptyDataInfo:数据为空时，可提示自定义的数据为空的提示信息
   successInfo:请求成功的消息提示，默认使用后台返回的消息进行提示，
   hideSuccessTip:是否显示请求成功的提示，默认显示提示信息
   useDesc:是否启用后台返回的desc字段作为提示信息
   hideErrorTip:是否显示请求错误的提示，默认显示提示信息
   redirectUrl:报403或者401错误时，重定向页面的路由
   redirectInterval:报403或者401错误时，重定向页面的路由等候的时间，默认3s
   messageKey:后台放置提示消息的字段
   dataKey:后台放置前台需求数据的字段
 */
 //根据项目需求，进一步封装axios.js，主要是减少写提示消息的相关代码
let defaultHttpConfig = {
    options: {  withCredentials: true },
    fullSuccess: false,
    ignoreEmptyData: false,
    hideEmptyTip: false,
    showEmptyInfo:false,
    emptyDataInfo: null,
    successInfo: null,
    hideSuccessTip: false,
    useDesc: false,
    hideErrorTip: false,
    redirectUrl:'/login',
    redirectInterval:3000,
    messageKey: 'message',
    dataKey: 'value'
};
    /**
    * @param
    *  type:默认值 get ，请求类型，默认只有四种，大小写均可.
    *  url:默认值 null ，请求后台的url.
    *  param: {},  默认值{} ,请求后台的参数 requestBody；如果参数是requestParameter，则可以追加在url后，也可以放在options里{params:HttpParams}
    *  configOptions: 默认值 defaultHttpConfig
    **/
let httpRequest = function(type = 'get',url= null,param = {}, configOptions = {}) {
    const requestType = type.toLowerCase();
    let defaultOptions = JSON.parse(JSON.stringify(defaultHttpConfig)); //使用clone保证不更改默认config
      //传递Authorization
      let userInfo =  sessionStorage.getItem('userInfo');
      if(userInfo != null &&  userInfo != undefined && userInfo != '{}'){
        defaultOptions.options.headers = {Authorization:JSON.parse(userInfo).Authorization};
      }
    let config = Object.assign(defaultOptions, configOptions); //默认config和传入的config合并
    //判断url是不是空，为空的话进行提示，不继续执行
    if(isEmpty(url)){
      Notification({ showClose: true,message: '必须传入请求后台的url', type: 'warning' });
        return;
    }
    let request = null; //axios返回的promise对象
    if(requestType == 'get' || requestType == 'delete'){
        request = axios[requestType](url,config.options);
    }else if(requestType == 'put' || requestType == 'post'){
        request = axios[requestType](url,param,config.options);
    }else {
      return;
    }
    //判断请求是不是空，为空的话进行提示，不继续执行
    if (request == null) {
      Notification({ showClose: true,message: '配置项配置错误，请检查配置项', type: 'warning' });
       return;
    }
    //再使用Promise进行返回，是因为接收到返回数据后会在Promise中进行部分数据判断等
    return new Promise((resolve,reject)=>{
       request.then((response) => {
           const res = response.data; //后台返回的数据
           //fullSuccess设置为true，则直接将后台返回的数据抛出；若为false，则再进行后续数据判断
           if (config.fullSuccess) {
              resolve(res);
           } else {
             //获取后台返回数据中前台使用的数据，dataKey一般为data或者value
              const data = res[config.dataKey];
             //后台返回response有status字段，前台需要判断status是否为200
              if(!isEmpty(res.status)){
                if(res['status'] == 200){
                  //不管数据是否为空，都将后台返回的前台使用的数据抛出
                  resolve(data);
                  if (!config.ignoreEmptyData) { //ignoreEmptyData设置为true，则不判断后台返回的前台使用的数据是否为空的情况，直接进行消息提示
                    //判断后台返回的前台使用的数据是否为空，空的情况包含null,undefined,'',[],{}；
                    if (isEmpty(data)) {
                      /* hideEmptyTip: 是否隐藏数据为空的消息提示，再保存更新数据时一般设置为true，不进行数据为空的消息提示
                         showEmptyInfo:是否使用后台返回的消息进行消息提示
                         emptyDataInfo：自定义数据为空的消息提示
                      */
                      !config.hideEmptyTip && (config.showEmptyInfo ? Notification({ showClose: true,message: res[config.messageKey], type: 'success' }): Notification({ showClose: true,message: config.emptyDataInfo ? config.emptyDataInfo : "数据为空", type: 'info' }));
                    } else {
                      //数据不为空，是否进行消息提示，hideSuccessTip为true时，不进行消息提示,successInfo:自定义的成功提示内容
                      !config.hideSuccessTip && Notification({ showClose: true,message: config.successInfo ?config.successInfo  : res[config.messageKey], type: 'success' });
                    }
                  } else {
                    !config.hideSuccessTip && Notification({ showClose: true,message: config.successInfo ?config.successInfo : res[config.messageKey], type: 'success' }); //是否进行消息提示
                  }
                }else{ //其他状态码的回调
                  reject(res); //将错误信息抛出
                  //是否进行错误消息提示，默认进行提示
                  if(!config.hideErrorTip){
                    let info = null;
                    //判断是否使用后台返回数据的desc字段值进行消息提示，默认使用messageKey字段中的值作为消息提示
                    if (config.useDesc) {
                      info = isEmpty(res["desc"]) ? res[config.messageKey] :res["desc"];
                    } else {
                      info = res[config.messageKey];
                    }
                    if(res.status == 403 || res.status == 401){
                      //提示redirectInterval秒后跳转至redirectUrl页面，默认跳转至登录页
                      Notification({ showClose: true,message: `${info}<br>${config.redirectInterval/1000}s后跳转至登录页`, type: 'warning',dangerouslyUseHTMLString:true });
                      //redirectInterval秒后进行redirectUrl页面跳转
                      let timer = setTimeout(() => {Vue.$router.push({path: config.redirectUrl });clearTimeout(timer);timer = null;}, config.redirectInterval);
                    }else{
                      Notification({ showClose: true,message: info, type: 'error' })
                    }
                  }
                }
              }else{ //后台返回response无status字段，进入此处则表示是成功回调（需要后台配合保证无status时，返回的是成功回调）
                resolve(data);
                if (!config.ignoreEmptyData) {//ignoreEmptyData设置为true，则不判断后台返回的前台使用的数据是否为空的情况，直接进行消息提示
                  if (isEmpty(data)) {
                    !config.hideEmptyTip && (config.showEmptyInfo ? Notification({ showClose: true,message: config.successInfo ?config.successInfo : res[config.messageKey], type: 'success' }) : Notification({ showClose: true,message: config.emptyDataInfo ? config.emptyDataInfo : "数据为空", type: 'info' }));
                  } else {
                    !config.hideSuccessTip && Notification({ showClose: true,message: config.successInfo ?config.successInfo : res[config.messageKey], type: 'success' });
                  }
                } else {
                  !config.hideSuccessTip && Notification({ showClose: true,message: config.successInfo ?config.successInfo : res[config.messageKey], type: 'success' });
                }
              }
           }
       }).catch(function (error) {
         //hideErrorTip：是否隐藏请求返回错误的消息提示
         if (config.hideErrorTip){
           reject(error);return;
         }else{
           const err = error.response;
           //判断错误消息的response是否存在，不存在则直接进行错误返回提示，404等错误会没有response
           if(!err){
             Notification({ showClose: true,message: error, type: 'error' });
             reject(error);
             return ;
           }
           const res = err.data;
           reject(res);
           //判断错误消息的response.data是否存在，不存在则直接进行错误返回提示statusText字段信息
           if (isEmpty(res)) {
             Notification({ showClose: true,message: err.statusText, type: 'error' });
             return;
           }
           let info = null;
           if (config.useDesc) {
             info = isEmpty(res["desc"]) ?res[config.messageKey] :res["desc"];
           } else {
             info = res[config.messageKey];
           }
           //判断后台返回的状态码是否是401或者403
           if (err.status == 403 || err.status == 401) { //权限不足
             Notification({ showClose: true,message: `${info}<br>${config.redirectInterval/1000}s后跳转至登录页`, type: 'warning',dangerouslyUseHTMLString:true });
             let timer = setTimeout(() => {Vue.$router.push({path: config.redirectUrl });clearTimeout(timer);timer = null;}, config.redirectInterval); //redirectInterval秒后进行redirectUrl页面跳转
           } else {
             Notification({ showClose: true,message: info, type: 'error' });
           }
         }
       })
    })
};

export default { httpRequest }
